use crate::map::Map;
use crate::bytes::Bytes;

use std::fmt::{self, Debug, Display};

use serde::ser::{self, SerializeSeq, SerializeMap};
use serde::de;


#[derive(Clone)]
pub enum Value {
    Bool(bool),
    Number(i64),
    Float(f64), 
    Bytes(Bytes),
    String(String),
    Array(Vec<Value>),
    Object(Map),
}


//TODO: to be optimize for easy use 
impl From<&[u8]> for Value {
    fn from(value: &[u8]) -> Self {
        Value::Bytes(Bytes::new(value))
    }
}

impl From<&str> for Value {
    fn from(value: &str) -> Self {
        Value::String(value.to_string())
    }
}
impl From<String> for Value {
    fn from(value: String) -> Self {
        Value::String(value)
    }
}

impl From<&[&str]> for Value {
    fn from(s: &[&str]) -> Self {
        Value::Array(s.iter()
            .map(|x| Value::from(*x))
            .collect::<Vec<Value>>()
        )
    }
}

impl ser::Serialize for Value {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> 
    where 
        S: ser::Serializer
    {
        match self {
            Value::Bool(b) => {
                serializer.serialize_bool(*b)
            }
            Value::Number(n) => {
                serializer.serialize_i64(*n)
            }
            Value::Float(f) => {
                serializer.serialize_f64(*f)
            }
            Value::String(s) => {
                serializer.serialize_str(s)
            }
            Value::Bytes(b) => {
                serializer.serialize_bytes(b.as_bytes())
            }
            Value::Array(v) => {
                let mut state = serializer.serialize_seq(Some(v.len()))?;
                v.iter()
                    .filter(|x| !x.is_empty())
                    .try_for_each(|e| state.serialize_element(e))?;
                state.end()
            }
            Value::Object(m) => {
                let mut state = serializer.serialize_map(Some(m.len()))?;

                m.iter()
                    .filter(|(_, y)| !y.is_empty() )
                    .try_for_each(|(x, y)| state.serialize_entry(x, y))?;
                state.end()
            }
        }//match 
    }
}



impl Debug for Value {
    #[inline]
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
       match self {
           Value::Bool(b) => write!(formatter, "Bool({})", b),
           Value::Number(n) => write!(formatter, "Number({})", n),
           Value::Float(f) => write!(formatter, "Float({})", f),
           Value::String(s) => write!(formatter, "String({})", s),
           Value::Bytes(b) => write!(formatter, "Bytes({:?})", b),
           Value::Array(v) => {
               formatter.write_str("Array: ")?;
               Debug::fmt(&v, formatter)
           }
           Value::Object(m) => { 
               formatter.write_str("Object: ")?;
               Debug::fmt(&m, formatter)
           }
       }
   }
}
impl Display for Value {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let s = crate::to_string(self).map_err(|_| fmt::Error)?;
        write!(f, "{}", s)
    }
}

impl PartialEq for Value {
    fn eq(&self, other: &Self) -> bool {
        match (self, other) {
            (Value::Bool(a), Value::Bool(b)) => a == b,
            (Value::Number(a), Value::Number(b)) =>  a == b,
            (Value::Float(a), Value::Float(b)) => a == b,
            (Value::String(a), Value::String(b)) => a == b,
            (Value::Bytes(a), Value::Bytes(b)) => a == b,
            (Value::Array(a), Value::Array(b)) => a == b,
            (Value::Object(a), Value::Object(b)) => a == b,
            _ => false
       }
    }
}
impl Eq for Value {}


impl Value {
    #[inline]
    pub fn is_empty(&self) -> bool {
        match self {
            Value::String(s) => s.is_empty(),
            Value::Bytes(b) => b.is_empty(),
            Value::Array(a)  => a.is_empty(),
            Value::Object(m) => m.is_empty(),
            _ => false,
        }
    }
    
    #[inline]
    pub fn as_str(&self) -> Option<&str> {
        match self {
            Value::String(ref s) => Some(s),
            _ => None,
        }
    }
    #[inline]
    pub fn as_str_mut(&mut self) -> Option<&mut String> {
        match self {
            Value::String(s) => Some(s),
            _ => None,
        }
    }
    #[inline]
    pub fn is_string(&self) -> bool {
        self.as_str().is_some()
    }

    pub fn as_bytes(&self) -> Option<& Bytes> {
        match self {
            Value::Bytes(b) => Some(b),
            _ => None,
        }
    }
    pub fn as_bytes_mut(&mut self) -> Option<&mut Bytes> {
        match self {
            Value::Bytes(b) => Some(b),
            _ => None,
        }
    }
    pub fn is_bytes(&self) -> bool {
        self.as_bytes().is_some()
    }

    #[inline]
    pub fn as_array(&self) -> Option<&Vec<Value>> {
        match self {
            Value::Array(v) => Some(v),
            _ => None,
        }
    }
    #[inline]
    pub fn as_array_mut(&mut self) -> Option<&mut Vec<Value>> {
        match self {
            Value::Array(v) => Some(v),
            _ => None,
        }
    }
    #[inline]
    pub fn is_array(&self) -> bool {
        self.as_array().is_some()
    }

    #[inline]
    pub fn as_object(&self) -> Option<&Map> {
        match self {
            Value::Object(m) => Some(m),
            _ => None,
        }
    }
    #[inline]
    pub fn as_object_mut(&mut self) -> Option<&mut Map> {
        match self {
            Value::Object(m) => Some(m),
            _ => None,
        }
    }
    #[inline]
    pub fn is_object(&self) -> bool {
        self.as_object().is_some()
    }

    #[inline]
    pub fn as_number(&self) -> Option<i64> {
        match self {
            Value::Number(n) => Some(*n),
            _ => None,
        }
    }
    #[inline]
    pub fn is_number(&self) -> bool {
        self.as_number().is_some()
    }
    #[inline]
    pub fn as_float(&self) -> Option<f64> {
        match self {
            Value::Float(f) => Some(*f),
            _ => None
        }
    }
    #[inline]
    pub fn is_float(&self) -> bool {
        self.as_float().is_some()
    }

    #[inline]
    pub fn as_bool(&self) -> Option<bool> {
        match self {
            Value::Bool(b) => Some(*b),
            _ => None
        }
    }
    #[inline]
    pub fn is_bool(&self) -> bool {
        self.as_bool().is_some()
    }
}

impl<'de> de::Deserialize<'de> for Value {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: de::Deserializer<'de>,
    {
        let content = <serde::__private::de::Content as de::Deserialize>::deserialize(deserializer)?;
        let deserializer = serde::__private::de::ContentRefDeserializer::<D::Error>::new(&content);

        if let Ok(ok) =<Vec<Value> as de::Deserialize>::deserialize(deserializer).map(Value::Array){
            return Ok(ok);
        }
        if let Ok(ok) = <Bytes as de::Deserialize>::deserialize(deserializer).map(Value::Bytes) {
            return Ok(ok);
        }
        if let Ok(ok) = <Map as de::Deserialize>::deserialize(deserializer).map(Value::Object) {
            return Ok(ok);
        }
        Err(de::Error::custom("data did not match any variant of untagged enum Value"))
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use crate::from_str;
    #[test]
    fn as_str() {
        {
            let v = Value::String("hello".to_string());
            assert!(v.is_string());
            assert_eq!(Some("hello"), v.as_str());
            assert_eq!(Some("hello"), v.as_str());
        }

        {
            let mut v = Value::String("hello".to_string());
            v.as_str_mut().unwrap().push_str("hello");
            assert!(v.is_string());
        }
    }

    #[test]
    fn value_serialize(){
        let v = Value::String("hello".to_string());
        assert_eq!("hello", crate::to_string(&v).unwrap());

        let v = Value::Array(vec![Value::Number(1), Value::Number(2), Value::Number(3)]);
        assert_eq!("[1,2,3]", crate::to_string(&v).unwrap());

        let v = Value::Array(vec![]);
        assert_eq!("", crate::to_string(&v).unwrap());

        let v = Value::Bytes(Bytes::new(&b"hello"[..]));
        assert_eq!("hello", crate::to_string(&v).unwrap());

        let v = Value::Bytes(Bytes::new(&b"hello"[..]));
        assert_eq!(&b"hello"[..], crate::to_vec(&v).unwrap());
    }

    #[test]
    fn value_deserialize(){
        let src = "String";
        let v: Value = from_str(src).unwrap();
        assert_eq!(v, Value::from(&b"String"[..]));

        let src = "0";
        let v: Value = from_str(src).unwrap();
        assert_eq!(v, Value::from(&b"0"[..]));

        let src = "-10";
        let v: Value = from_str(src).unwrap();
        assert_eq!(v, Value::from(&b"-10"[..]));

        let src = "0.1";
        let v: Value = from_str(src).unwrap();
        assert_eq!(v, Value::from(&b"0.1"[..]));

        let src = "-0.1";
        let v: Value = from_str(src).unwrap();
        assert_eq!(v, Value::from(&b"-0.1"[..]));

        let src = "[]";
        let v: Value = from_str(src).unwrap();
        let expect = Value::Array(vec![]);
        assert_eq!(v, expect);

        let src = "[v1]";
        let v: Value = from_str(src).unwrap();
        let expect: Value = Value::Array(vec![Value::from(&b"v1"[..])]);
        assert_eq!(v, expect);

        let src = "{}";
        let v: Value = from_str(src).unwrap();
        let map = Map::new();
        let expect: Value = Value::Object(map);
        assert_eq!(v, expect);

        let src = "{key=0.11}";
        let v: Value = from_str(src).unwrap();
        
        let mut map = Map::new();
        map.insert_kstr_vbytes("key", &b"0.11"[..]);
        let expect: Value = Value::Object(map);

        assert_eq!(v, expect);


        let src = "00000";
        let v: Value = from_str(src).unwrap();
        assert_eq!(v, Value::from(&b"00000"[..]));
    }


    #[test]
    fn from_trait() {
        let v = Value::from("string");
        assert_eq!(Value::String("string".to_string()), v);

        let expect = Value::Array(vec![Value::from("string"), Value::from("string")]);
        assert_eq!(expect, Value::from(&["string", "string"][..]));
    }
}
